package com.young.gpg.common.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.Objects;

/**
 * @description：
 * @author: yangyahui01
 * @date: 12/4/24 5:14 PM
 */
@Component
@Slf4j
public class CommandServiceImpl implements CommandService {

    @Override
    public String command(String command) {
        return null;
    }

    /**
     * 签名+加密
     *
     * @param file      被签名加密的文件
     * @param localUser 发信者ID,用发信者的私钥签名
     * @param recipient 接收者ID,用接收者的公钥加密
     * @param password  密码（这个可以不用写）
     * @return
     */
    @Override
    public boolean gpgSignAndEncrypt(String file, String localUser, String recipient, String password) {
        /**
         * 构造 gpg 命令
         * --armor：表示采用ASCII码形式显示
         * --sign：表示需要签名
         * --yes：自动回答“yes”以确认任何提示
         * --always-trust：不检查密钥是否信任，接受任何密钥
         * --batch：批处理模式，自动处理所有操作
         * -q：安静模式，减少输出
         * --no-tty：不使用TTY来获取密码或任何其他用户输入
         * --encrypt：加密文件
         */
        StringBuilder gpgCommand = new StringBuilder();

        if (Objects.nonNull(password)) {
            gpgCommand.append("/usr/local/bin/gpg --local-user \"")
                    .append(localUser)
                    .append("\" --recipient \"")
                    .append(recipient)
                    .append("\" --armor --sign --yes --always-trust --batch --passphrase \"")
                    .append(password)
                    .append("\" -q --no-tty --encrypt \"")
                    .append(file)
                    .append("\"");
        } else {
            gpgCommand.append("/usr/local/bin/gpg --local-user \"")
                    .append(localUser)
                    .append("\" --recipient \"")
                    .append(recipient)
                    .append("\" --armor --sign --yes --always-trust --batch -q --no-tty --encrypt \"")
                    .append(file)
                    .append("\"");

        }

        log.info("GPG ENCRYPT COMMAND: {}", gpgCommand.toString());

        String[] command = new String[]{"/bin/bash", "-c", gpgCommand.toString()};

        return execute(command);
    }


    private boolean execute(String[] command) {

        boolean success = true;

        try {
            Process gpgProcess = Runtime.getRuntime().exec(command);

            //关闭流释放资源
            if (gpgProcess != null) {
                gpgProcess.getOutputStream().close();
            }
            try {
                //等待GPG进程结束
                gpgProcess.waitFor();
            } catch (InterruptedException e2) {
                e2.printStackTrace();
            }

            BufferedReader gpgOutput = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream()));
            BufferedWriter gpgInput = new BufferedWriter(new OutputStreamWriter(gpgProcess.getOutputStream()));
            BufferedReader gpgErrorOutput = new BufferedReader(new InputStreamReader(gpgProcess.getErrorStream()));

            try {
                int code = gpgProcess.exitValue();

                log.info("GPG 命令返回码:{}", code);

                if (gpgOutput.ready()) {
                    log.info("GPG stream:\n{}", getStreamText(gpgOutput));
                }

                if (gpgErrorOutput.ready()) {
                    String error = getStreamText(gpgErrorOutput);
                    log.info("GPG stream:\n {}", error);
                }
            } catch (Exception e) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e1) {
                    log.info("This thread has insomnia: {}", e1.getMessage());
                }
                success = false;
            }
        } catch (IOException e) {
            log.info("Error running GPG via runtime: {}", e.getMessage());
            success = false;
        }

        return success;

    }

    /**
     * 解密文件
     *
     * @param file           加密文件
     * @param newFile        新文件
     * @param passphraseFile 密码
     * @return
     */
    @Override
    public boolean gpgDecrypt(String file, String newFile, String passphraseFile) {
        String result = null;

        StringBuilder gpgCommand = new StringBuilder();

        gpgCommand.append("/usr/local/bin/gpg --batch --passphrase \"")
                .append(passphraseFile)
                .append("\" -q --no-tty -o \"")
                .append(newFile)
                .append("\" -d \"")
                .append(file)
                .append("\"");


        log.info("GPG DECRYPT COMMAND: {}", gpgCommand.toString());
        String[] command = new String[]{"/bin/sh", "-c", gpgCommand.toString()};
        return execute(command);
    }

    @Override
    public boolean string2File(String res, String filePath) {
        return false;
    }

    @Override
    public void startGpg() {
        String[] command = new String[]{"/bin/sh","-c", "/usr/local/MacGPG2/bin/gpg-agent --daemon --use-standard-socket"};
        boolean execute = execute(command);
        log.info("start GPG:{}", execute);
    }

    private String getStreamText(BufferedReader reader) throws IOException {
        StringBuilder result = new StringBuilder();
        try {
            while (reader.ready()) {
                result.append(reader.readLine());
                if (reader.ready()) {
                    result.append("\n");
                }
            }
        } catch (IOException ioe) {
            log.info("Error while reading the stream: " + ioe.getMessage());
            throw ioe;
        }
        return result.toString();
    }
}
